{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载模块\n",
    "from datetime import datetime\n",
    "\n",
    "# 统计分析\n",
    "import pandas as pd\n",
    "from statsmodels.api import OLS\n",
    "from statsmodels.tsa.stattools import coint\n",
    "\n",
    "# 画图\n",
    "import plotly.graph_objects as go\n",
    "\n",
    "# 读数据\n",
    "from vnpy.trader.database import database_manager\n",
    "from vnpy.trader.utility import extract_vt_symbol\n",
    "from vnpy.trader.constant import Interval"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义函数 读取合约代码  k 最高最低价是没意义的，只要收盘和开盘价\n",
    "def load_symbol_data(vt_symbol, start, end):\n",
    "    symbol, exchange = extract_vt_symbol(vt_symbol)\n",
    "    start = datetime.strptime(start, \"%Y%m%d\")\n",
    "    end = datetime.strptime(end, \"%Y%m%d\")\n",
    "    interval = Interval.MINUTE\n",
    "    data = database_manager.load_bar_data(symbol, exchange, interval, start, end)\n",
    "    \n",
    "    dt_list = []\n",
    "    close_list = []\n",
    "    for bar in data:\n",
    "        dt_list.append(bar.datetime)\n",
    "        close_list.append(bar.close_price)\n",
    "    \n",
    "    s = pd.Series(close_list, index=dt_list)\n",
    "    return s\n",
    "\n",
    "\n",
    "def load_portfolio_data(vt_symbols, start, end):\n",
    "    df = pd.DataFrame()\n",
    "    for vt_symbol in vt_symbols:\n",
    "        s = load_symbol_data(vt_symbol, start, end)\n",
    "        df[vt_symbol] = s\n",
    "    return df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Empty DataFrame\n",
      "Columns: [XBTUSD.BITMEX, btcusdt.BINANCE]\n",
      "Index: []\n"
     ]
    }
   ],
   "source": [
    "# 加载数据\n",
    "vt_symbols = [\"XBTUSD.BITMEX\", \"btcusdt.BINANCE\"]\n",
    "start = \"20200101\"\n",
    "end = \"20200630\"\n",
    "\n",
    "df = load_portfolio_data(vt_symbols, start, end)\n",
    "print(df)    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 绘制原始价格图表\n",
    "fig = go.Figure()\n",
    "\n",
    "for vt_symbol in vt_symbols:\n",
    "    line = go.Scatter(y=df[vt_symbol], mode='lines', name=vt_symbol)\n",
    "    fig.add_trace(line)\n",
    "    \n",
    "fig.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "# 执行回归分析\n",
    "result = OLS(df[vt_symbols[0]], df[vt_symbols[-1]]).fit()\n",
    "print(result.summary())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对残差绘图\n",
    "df[\"spread\"] = df[vt_symbols[0]] - 1 * df[vt_symbols[-1]]\n",
    "\n",
    "fig = go.Figure()\n",
    "line = go.Scatter(x=df.index, y=df[\"spread\"], mode='lines', name=\"Spread\")\n",
    "fig.add_trace(line)\n",
    "    \n",
    "fig.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# 执行协整检验\n",
    "score, pvalue, _ = coint(df[vt_symbols[0]], df[vt_symbols[-1]])\n",
    "print(f\"协整分析的p-value为：{pvalue}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## p-value如果小于0.05，则可以明确证明协整关系，但在实践中非常少见。价差整体上还是存在大量的均值偏移情况，但只要震荡回归的次数足够多，即使不满足协整也能通过交易盈利。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
